package com.demo.lengthFieldBasedFrameDecoder.demo1;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class NettyServer {
    private Logger log = LoggerFactory.getLogger(NettyServer.class);

    public static void main(String[] args) {

        NettyServer nettyServer = new NettyServer();
        nettyServer.start(8888);
    }

    private void start(int port) {
        NioEventLoopGroup boss = new NioEventLoopGroup(1);
        NioEventLoopGroup worker = new NioEventLoopGroup();

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(boss, worker)
                    .channel(NioServerSocketChannel.class)
                    //给boss添加handler
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        protected void initChannel(SocketChannel ch) {
                            ChannelPipeline pipeline = ch.pipeline();
                            //发送的数据包最大长度为1024*64
                            //length域的偏移,正常情况下读取数据从偏移为0处开始读取,如果有需要可以从其他偏移量处开始读取,看自己的定义，长度域前面是否还有指令
                            //length域占用的字节数
                            //在length域和content域中间是 否需要填充其他字节数，lengthAdjustment =0，内容长度，-3 s就是只读lengght代表的长度度-3个长度了，就是后面的正文的长度了
                            //（因为长度域为总长度包含了长度域的两个字节数。），所以我们需要修正数据长度，也就是减去2，数据长度的修正。-2
                            //解码后跳过的字节数 ( 解码后把 length占用的字节跳过，直接传数据包)，length 的指令跳过多少指令，为正数，
                            //解码真跳过前面的4个字节数，就是正文的body了
                            pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
                            pipeline.addLast(new MySimpleChannelInboundHandler());
                        }
                    });
            //绑定端口
            ChannelFuture future = serverBootstrap.bind(port).sync();
            //监听端口的关闭
            future.channel().closeFuture().sync();
        } catch (Exception e) {
            log.error("netty server error ,{}", e.getMessage(), e);
        } finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }
}
